﻿using System;
using System.Collections.Generic;
using UnityEngine;
using VoxelBlock.VoxelBlock3D;
using VoxelBlock;using Vector3Int = VoxelBlock.Vector3Int;

public class OperationImplementSliceAdd : OperationImplement
{
    /// <summary>
    /// 尝试性添加或删除
    /// </summary>
    Dictionary<Vector3Int, Voxel3D> attemptDictionaryVoxels = new Dictionary<Vector3Int, Voxel3D>();

    /// <summary>
    /// 空白区域边界判断条件
    /// </summary>
    Func<Vector3Int, bool> FuncIsContinue;

    /// <summary>
    /// 获得空白区域边界判断条件
    /// </summary>
    Func<Func<Vector3Int, bool>> getFuncIsContinue;

    int oldlayer = 0;

    int startLayer = 0;
    GameObject meshSliceCollider;
    Transform mainCameraY;

    StartSliceArg startSliceArg;

    /// <summary>
    /// 一样的颜色才可以
    /// </summary>
    int mSliceUVxy;
    /// <summary>
    /// 对一片进行操作时保存6个方向中的一个
    /// </summary>
    VoxelDirection sliceDirection;

    Func<VoxelDirection> SetSliceDirection;

    /// <summary>
    /// 对一片进行操作时保存6个方向中的一个
    /// </summary>
    Vector3Int meshSliceXYZ = new Vector3Int();
    Dictionary<Vector3Int, Vector3Int> mSlicesBlocks = new Dictionary<Vector3Int, Vector3Int>();
    Dictionary<Vector3Int, int> mSlicesBlocks2 = new Dictionary<Vector3Int, int>();
    Vector3Int[] mainSlicesBlocks;
    int[] mainSlicesKeys;

    bool isNull = false;

    public OperationImplementSliceAdd(GameObject meshSliceCollider
        , Transform mainCameraY , Func<VoxelDirection> setSliceDirection
        , Func<Func<Vector3Int, bool>> getFuncIsContinue)
    {
        this.meshSliceCollider = meshSliceCollider;
        this.mainCameraY = mainCameraY;
        this.SetSliceDirection = setSliceDirection;
        this.getFuncIsContinue = getFuncIsContinue;
    }


    public override void Start(StartArg arg)
    {
        startSliceArg = arg.startSliceArg;
        base.Start(arg);

        FuncIsContinue = getFuncIsContinue();
        StartMethod(arg.StartPosition, arg.nowSelectUVKey);
    }

    private void StartMethod(Vector3Int StartPosition, int nowSelectUVKey)
    {
        sliceDirection = SetSliceDirection();
        Vector3 bPosition = StartPosition;
        meshSliceCollider.gameObject.SetActive(true);
        meshSliceCollider.transform.position = bPosition;// new Vector3();
        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                bPosition -= new Vector3(1, 0, 0);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                break;
            case VoxelDirection.Left:
                bPosition += new Vector3(1, 0, 0);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                break;
            case VoxelDirection.Up:
                bPosition -= new Vector3(0, 1, 0);
                meshSliceCollider.transform.eulerAngles = new Vector3(0, mainCameraY.eulerAngles.y, 0);
                break;
            case VoxelDirection.Down:
                bPosition += new Vector3(0, 1, 0);
                meshSliceCollider.transform.eulerAngles = new Vector3(0, mainCameraY.eulerAngles.y, 0);
                break;
            case VoxelDirection.Front:
                bPosition -= new Vector3(0, 0, 1);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                break;
            case VoxelDirection.Break:
                bPosition += new Vector3(0, 0, 1);
                meshSliceCollider.transform.eulerAngles = new Vector3(90, 0, 0);
                break;
            default:
                break;
        }

        isNull = false;
        mSlicesBlocks.Clear();// = new Dictionary<Vector3Int, Vector3Int>();
        mSlicesBlocks2.Clear();
        if (nowDrawVoxel3DCore.allVoxels.ContainsKey(bPosition))
        {
            mSliceUVxy = nowDrawVoxel3DCore.allVoxels[bPosition].uvKey;
            BasicAlgorithm.GetSliceBlock(mSlicesBlocks2, sliceDirection, bPosition, mSliceUVxy, nowDrawVoxel3DCore.allVoxels, startSliceArg.Is8, startSliceArg.GetColor);
        }
        else
        {
            bPosition = StartPosition;
            mSliceUVxy = nowSelectUVKey;
            BasicAlgorithm.GetSliceBlock(mSlicesBlocks, sliceDirection, bPosition, nowDrawVoxel3DCore.allVoxels, FuncIsContinue);
            isNull = true;
        }

        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                meshSliceXYZ = new Vector3Int(1, 0, 0);
                startLayer = (int)bPosition.x;
                oldlayer = (int)bPosition.x - startLayer;
                break;
            case VoxelDirection.Left:
                meshSliceXYZ = new Vector3Int(-1, 0, 0);
                startLayer = (int)bPosition.x;
                oldlayer = -(int)bPosition.x + startLayer;
                break;
            case VoxelDirection.Up:
                meshSliceXYZ = new Vector3Int(0, 1, 0);
                startLayer = (int)bPosition.y;
                oldlayer = (int)bPosition.y - startLayer;
                break;
            case VoxelDirection.Down:
                meshSliceXYZ = new Vector3Int(0, -1, 0);
                startLayer = (int)bPosition.y;
                oldlayer = -(int)bPosition.y + startLayer;
                break;
            case VoxelDirection.Front:
                meshSliceXYZ = new Vector3Int(0, 0, 1);
                startLayer = (int)bPosition.z;
                oldlayer = (int)bPosition.z - startLayer;
                break;
            case VoxelDirection.Break:
                meshSliceXYZ = new Vector3Int(0, 0, -1);
                startLayer = (int)bPosition.z;
                oldlayer = -(int)bPosition.z + startLayer;
                break;
        }
        if (isNull)
        {
            mainSlicesBlocks = new Vector3Int[mSlicesBlocks.Count];
            int blockIndex = 0;
            foreach (var item in mSlicesBlocks.Values)
            {
                mainSlicesBlocks[blockIndex] = item - meshSliceXYZ;
                blockIndex++;
            }
        }
        else
        {
            mainSlicesKeys = new int[mSlicesBlocks2.Count];
            mainSlicesBlocks = new Vector3Int[mSlicesBlocks2.Count];
            int blockIndex = 0;
            foreach (var item in mSlicesBlocks2)
            {
                mainSlicesBlocks[blockIndex] = item.Key;
                mainSlicesKeys[blockIndex] = item.Value;
                blockIndex++;
            }
        }

        return;
        Voxel3D[] array = new Voxel3D[mainSlicesBlocks.Length];
        //int index = 0;

        for (int i = 0; i < mainSlicesBlocks.Length; i++)
        {
            Vector3Int position = mainSlicesBlocks[i] + meshSliceXYZ;
            if (startSliceArg.SetColor)
            {
                array[i] = new Voxel3D(position, nowSelectUVKey);
            }
            else
            {
                array[i] = new Voxel3D(position, mainSlicesKeys[i]);
            }
            if (nowDrawVoxel3DCore.allVoxels.ContainsKey(position))
            {
                //有的话就不重复添加
            }
            else
            {
                attemptDictionaryVoxels[position] = array[i];
                //index++;
            }
        }

        nowDrawVoxel3DCore.DrawAddBlock(array);

        //if (isNull)
        //{
        //    foreach (Vector3Int position in mSlicesBlocks.Values)
        //    {
        //        array[index] = new Voxel3D(position, nowSelectUVKey);
        //        attemptDictionaryVoxels[position] = array[index];
        //        index++;
        //    }
        //}
        //else
        //{
        //    foreach (Vector3Int position in mSlicesBlocks.Values)
        //    {
        //        array[index] = new Voxel3D(position + meshSliceXYZ, nowSelectUVKey);
        //        attemptDictionaryVoxels[position + meshSliceXYZ] = array[index];
        //        index++;
        //    }
        //}
    }

    public override void Run(RunArg arg)
    {
        Vector3Int bPosition = arg.nowSelectPosition;
        int sliceLayer = 0;
        switch (sliceDirection)
        {
            case VoxelDirection.Right:
                sliceLayer = (int)bPosition.x - startLayer;
                break;
            case VoxelDirection.Left:
                sliceLayer = -(int)bPosition.x + startLayer;
                break;
            case VoxelDirection.Up:
                sliceLayer = (int)bPosition.y - startLayer;
                break;
            case VoxelDirection.Down:
                sliceLayer = -(int)bPosition.y + startLayer;
                break;
            case VoxelDirection.Front:
                sliceLayer = (int)bPosition.z - startLayer;
                break;
            case VoxelDirection.Break:
                sliceLayer = -(int)bPosition.z + startLayer;
                break;
        }
        if (oldlayer == sliceLayer || sliceLayer <= 0)
        {
            return;
        }

        if (oldlayer < sliceLayer)
        {
            List<Voxel3D> arrayVoxel3D = new List<Voxel3D>(mainSlicesBlocks.Length * (sliceLayer - oldlayer));
            for (int i = oldlayer + 1; i <= sliceLayer; i++)
            {
                for (int j = 0; j < mainSlicesBlocks.Length; j++)
                {
                    Vector3Int position = mainSlicesBlocks[j];
                //}
                //foreach (Vector3Int position in mainSlicesBlocks)
                //{
                    var key = position + meshSliceXYZ * i;
                    if (nowDrawVoxel3DCore.allVoxels.ContainsKey(key))
                    {
                        //有的话就不重复添加
                    }
                    else
                    {
                        Voxel3D voxel;
                        if (isNull)
                        {
                            voxel = new Voxel3D(key, arg.nowSelectUVKey);
                        }
                        else
                        {
                            if (startSliceArg.SetColor)
                            {
                                voxel = new Voxel3D(key, arg.nowSelectUVKey);
                            }
                            else
                            {
                                voxel = new Voxel3D(key, mainSlicesKeys[j]);
                            }
                        }
                        attemptDictionaryVoxels[key] = voxel;
                        arrayVoxel3D.Add(voxel);
                    }
                }
            }
            nowDrawVoxel3DCore.DrawAddBlock(arrayVoxel3D);
        }
        else
        {
            List<Vector3Int> arrayVector3Int = new List<Vector3Int>(mainSlicesBlocks.Length * (oldlayer - sliceLayer));
            for (int i = oldlayer; i >= sliceLayer + 1; i--)
            {
                foreach (Vector3Int position in mainSlicesBlocks)
                {
                    var key = position + meshSliceXYZ * i;
                    if (attemptDictionaryVoxels.ContainsKey(key))
                    {
                        arrayVector3Int.Add(key);
                        attemptDictionaryVoxels.Remove(key);
                    }
                }
            }
            nowDrawVoxel3DCore.DrawRemoveBlock(arrayVector3Int);
        }

        oldlayer = sliceLayer;
    }

    public override void Over(OverArg arg)
    {
        meshSliceCollider.gameObject.SetActive(false);
        if (isStop)
        {

        }
        else
        {
            StartMethod(arg.gestureStartPosition, arg.nowSelectUVKey);

            List<SimpleVoxel> arrayVoxel3D = new List<SimpleVoxel>(attemptDictionaryVoxels.Count);
            foreach (var item in attemptDictionaryVoxels.Values)
            {
                arrayVoxel3D.Add(new SimpleVoxel(item.worldPosition, item.uvKey, item.selectKey));
            }
            if (arrayVoxel3D.Count > 0)
            {
                proxy.Write(VoxelCategories.Operation.Add, historyRecordFrontList, arrayVoxel3D);
                historyRecordBreakList = new List<SimpleVoxel>();
                historyRecordFrontList = new List<SimpleVoxel>();
            }
            attemptDictionaryVoxels.Clear();
        }
        meshSliceCollider.gameObject.SetActive(false);

    }

}
